// Copyright Epic Games, Inc. All Rights Reserved.

#include "zenutil/workerpools.h"

#include <zencore/intmath.h>
#include <zencore/thread.h>

ZEN_THIRD_PARTY_INCLUDES_START
#include <gsl/gsl-lite.hpp>
ZEN_THIRD_PARTY_INCLUDES_END

namespace zen {
namespace {
	const int LargeWorkerThreadPoolTreadCount  = gsl::narrow<int>(std::thread::hardware_concurrency());
	const int MediumWorkerThreadPoolTreadCount = gsl::narrow<int>(Max((std::thread::hardware_concurrency() / 4u), 2u));
	const int SmallWorkerThreadPoolTreadCount  = gsl::narrow<int>(Max((std::thread::hardware_concurrency() / 8u), 1u));

	static bool IsShutDown = false;

	RwLock PoolLock;

	std::unique_ptr<WorkerThreadPool> LargeWorkerPool;
	std::unique_ptr<WorkerThreadPool> MediumWorkerPool;
	std::unique_ptr<WorkerThreadPool> SmallWorkerPool;
	std::unique_ptr<WorkerThreadPool> SyncWorkerPool;
}  // namespace

WorkerThreadPool&
GetLargeWorkerPool()
{
	{
		RwLock::SharedLockScope _(PoolLock);
		if (LargeWorkerPool)
		{
			return *LargeWorkerPool;
		}
	}
	RwLock::ExclusiveLockScope _(PoolLock);
	ZEN_ASSERT(!IsShutDown);
	if (LargeWorkerPool)
	{
		return *LargeWorkerPool;
	}
	LargeWorkerPool.reset(new WorkerThreadPool(LargeWorkerThreadPoolTreadCount, "LargeThreadPool"));
	return *LargeWorkerPool;
}

WorkerThreadPool&
GetMediumWorkerPool()
{
	{
		RwLock::SharedLockScope _(PoolLock);
		if (MediumWorkerPool)
		{
			return *MediumWorkerPool;
		}
	}
	RwLock::ExclusiveLockScope _(PoolLock);
	ZEN_ASSERT(!IsShutDown);
	if (MediumWorkerPool)
	{
		return *MediumWorkerPool;
	}
	MediumWorkerPool.reset(new WorkerThreadPool(MediumWorkerThreadPoolTreadCount, "MediumThreadPool"));
	return *MediumWorkerPool;
}

WorkerThreadPool&
GetSmallWorkerPool()
{
	{
		RwLock::SharedLockScope _(PoolLock);
		if (SmallWorkerPool)
		{
			return *SmallWorkerPool;
		}
	}
	RwLock::ExclusiveLockScope _(PoolLock);
	ZEN_ASSERT(!IsShutDown);
	if (SmallWorkerPool)
	{
		return *SmallWorkerPool;
	}
	SmallWorkerPool.reset(new WorkerThreadPool(SmallWorkerThreadPoolTreadCount, "SmallThreadPool"));
	return *SmallWorkerPool;
}

WorkerThreadPool&
GetSyncWorkerPool()
{
	{
		RwLock::SharedLockScope _(PoolLock);
		if (SyncWorkerPool)
		{
			return *SyncWorkerPool;
		}
	}
	RwLock::ExclusiveLockScope _(PoolLock);
	ZEN_ASSERT(!IsShutDown);
	if (SyncWorkerPool)
	{
		return *SyncWorkerPool;
	}
	SyncWorkerPool.reset(new WorkerThreadPool(0, "SyncThreadPool"));
	return *SyncWorkerPool;
}

void
ShutdownWorkerPools()
{
	RwLock::ExclusiveLockScope _(PoolLock);
	IsShutDown = true;
	LargeWorkerPool.reset();
	MediumWorkerPool.reset();
	SmallWorkerPool.reset();
	SyncWorkerPool.reset();
}
}  // namespace zen
